package gouhuo.allbugs.top.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import gouhuo.allbugs.top.common.BusinessException;
import gouhuo.allbugs.top.common.ErrorCode;
import gouhuo.allbugs.top.mapper.FriendsMapper;
import gouhuo.allbugs.top.model.domain.Friends;
import gouhuo.allbugs.top.model.request.friends.FriendHandleRequest;
import gouhuo.allbugs.top.model.request.friends.FriendUpdateRequest;
import gouhuo.allbugs.top.model.vo.FriendsMsgVO;
import gouhuo.allbugs.top.model.vo.FriendsVO;
import gouhuo.allbugs.top.service.FriendsService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static gouhuo.allbugs.top.constant.RedisConstants.*;

/**
 * @author 15294780204
 * @description 针对表【friends(好友表)】的数据库操作Service实现
 * @createDate 2023-05-01 18:07:13
 */
@Service
public class FriendsServiceImpl extends ServiceImpl<FriendsMapper, Friends>
        implements FriendsService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Long friendMsg(FriendsMsgVO friendsMsgVO) {
        Long userId = friendsMsgVO.getUserId();
        Long friendId = friendsMsgVO.getFriendId();
        String friendName = friendsMsgVO.getFriendName();
        String friendUrl = friendsMsgVO.getFriendUrl();
        if (userId == null || friendId == null || StringUtils.isAnyBlank(friendUrl, friendName)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (friendsMsgVO.getNote() == null) {
            friendsMsgVO.setNote(friendName);
        }
        if (userId == 1) {
            QueryWrapper<Friends> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("userId", userId).eq("friendId", friendId);
            Friends friends = BeanUtil.copyProperties(friendsMsgVO, Friends.class);
            if (getOne(queryWrapper) == null) {
                friends.setFriendUrl(friendUrl);
                friends.setNote(friendName);
                boolean save1 = save(friends);
                if (!save1) throw new BusinessException(ErrorCode.SYSTEM_ERROR);
            }
            queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("userId", friendId).eq("friendId", userId);
            if (getOne(queryWrapper) == null) {
                friends.setId(null);
                friends.setUserId(friendId);
                friends.setFriendId(userId);
                friends.setFriendUrl(friendsMsgVO.getUserUrl());
                friends.setNote(friendsMsgVO.getUserName());
                boolean save2 = save(friends);
                if (!save2) throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                Set<String> keys = stringRedisTemplate.keys(FRIENDS_LIST_KEY + friendId + ":*");
                if (keys != null) {
                    stringRedisTemplate.delete(keys);
                }
            }
            return 1L;
        }
        if (friendsMsgVO.getStatus() == null) {
            friendsMsgVO.setStatus(0);
        }
        SetOperations<String, String> opsForSet = stringRedisTemplate.opsForSet();
        String key = FRIENDS_MSG_KEY + userId + ":friendMsg" + friendId;
        String friendVO = new Gson().toJson(friendsMsgVO);
        Boolean member = opsForSet.isMember(key, friendVO);
        if (Boolean.TRUE.equals(member)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "无需重复申请");
        }
        opsForSet.pop(key);
        return opsForSet.add(key, friendVO);
    }

    @Override
    public List<FriendsMsgVO> msgList(Long userId) {
        String key = FRIENDS_MSG_KEY + userId + ":*";
        Set<String> keys = stringRedisTemplate.keys(key);
        if (keys == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "申请列表查询失败");
        }
        List<FriendsMsgVO> list = new ArrayList<>();
        if (keys.size() == 0) return list;
        for (String k : keys) {
            Set<String> members = stringRedisTemplate.opsForSet().members(k);
            if (members == null) continue;
            for (String m : members) {
                FriendsMsgVO friendsMsgVO = new Gson().fromJson(m, FriendsMsgVO.class);
                list.add(friendsMsgVO);
            }
        }
        return list;
    }

    @Override
    @Transactional
    public Long handleMsg(FriendHandleRequest friendHandleRequest) {
        Long userId = friendHandleRequest.getUserId();
        String userUrl = friendHandleRequest.getUserUrl();
        Long friendId = friendHandleRequest.getFriendId();
        String friendUrl = friendHandleRequest.getFriendUrl();
        String userName = friendHandleRequest.getUserName();
        String note = friendHandleRequest.getNote();
        Integer status = friendHandleRequest.getStatus();
        if (userId == null || status == null || friendId == null || StringUtils.isAnyBlank(userUrl, userName, friendUrl, note)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (status == 1) {
            //以双方id为userId各插入一条记录
            QueryWrapper<Friends> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("userId", userId).eq("friendId", friendId);
            Friends friends = BeanUtil.copyProperties(friendHandleRequest, Friends.class);
            if (getOne(queryWrapper) == null) {
                friends.setFriendUrl(friendUrl);
                boolean save1 = save(friends);
                if (!save1) throw new BusinessException(ErrorCode.SYSTEM_ERROR);
            }
            queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("userId", friendId).eq("friendId", userId);
            if (getOne(queryWrapper) == null) {
                friends.setId(null);
                friends.setUserId(friendId);
                friends.setFriendId(userId);
                friends.setFriendUrl(userUrl);
                friends.setNote(userName);
                boolean save2 = save(friends);
                if (!save2) throw new BusinessException(ErrorCode.SYSTEM_ERROR);
            }
            Set<String> keys = stringRedisTemplate.keys(FRIENDS_LIST_KEY + userId + ":*");
            if (keys != null && !keys.isEmpty()) {
                stringRedisTemplate.delete(keys);
            }
        }
        String key = FRIENDS_MSG_KEY + userId + ":friendMsg" + friendId;
        SetOperations<String, String> opsForSet = stringRedisTemplate.opsForSet();
        Gson gson = new Gson();
        FriendsMsgVO friendsMsgVO = gson.fromJson(opsForSet.pop(key), FriendsMsgVO.class);
        friendsMsgVO.setStatus(status);
        return opsForSet.add(key, gson.toJson(friendsMsgVO));
    }

    @Override
    public List<FriendsVO> friendList(Long userId) {
        String key = FRIENDS_LIST_KEY + userId;
        List<FriendsVO> list = new ArrayList<>();
        Set<String> keys = stringRedisTemplate.keys(key + ":*");
        HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();
        if (keys != null && !keys.isEmpty()) {
            for (String k : keys) {
                Map<Object, Object> redisUserMap = opsForHash.entries(k);
                FriendsVO friendsVO = null;
                if (!redisUserMap.isEmpty()) {
                    friendsVO = BeanUtil.fillBeanWithMap(redisUserMap, new FriendsVO(), false);
                    //查询好友是否在线
                    Object obj = opsForHash.get(LOGIN_ONLINE_KEY, String.valueOf(friendsVO.getFriendId()));
                    if (obj != null) {
                        long time = Long.parseLong((String) obj);
                        friendsVO.setOnLine(time + 1800 > System.currentTimeMillis() / 1000 ? 1 : 0);
                    }
                }
                list.add(friendsVO);
            }
        } else {
            List<Friends> friendsList = list(new QueryWrapper<Friends>().eq("userId", userId));
            list = friendsList.stream().map(friend -> BeanUtil.copyProperties(friend, FriendsVO.class)).collect(Collectors.toList());
            list.forEach(friendsVO -> {
                String k = key + ":friend" + friendsVO.getFriendId();
                Map<String, Object> friendsMap = BeanUtil.beanToMap(friendsVO, new HashMap<>(),
                        CopyOptions.create() //在存储为map时要保证值全为String
                                .setIgnoreNullValue(true) //忽略空值
                                .setFieldValueEditor((fieldName, fieldValue) -> fieldValue == null ? "0" : fieldValue.toString()));
                //将该对象存储到redis
                stringRedisTemplate.opsForHash().putAll(k, friendsMap);
                //设置key的有效期
                stringRedisTemplate.expire(k, FRIENDS_LIST_TTL, TimeUnit.MINUTES);
            });
        }
        return list;
    }

    @Override
    public boolean friendUpdate(FriendUpdateRequest friendUpdateRequest) {
        Long id = friendUpdateRequest.getId();
        Long userId = friendUpdateRequest.getUserId();
        Long friendId = friendUpdateRequest.getFriendId();
        String note = friendUpdateRequest.getNote();
        if (id == null || userId == null || friendId == null || StrUtil.isBlank(note)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能为空");
        }
        boolean update = update().setSql("note='" + note + "'").eq("id", id).update();
        String key = FRIENDS_LIST_KEY + userId + ":friend";
        stringRedisTemplate.opsForHash().put(key + friendId, "note", note);
        return update;
    }

    @Override
    @Transactional
    public boolean friendDelete(FriendUpdateRequest friendUpdateRequest) {
        Long id = friendUpdateRequest.getId();
        Long userId = friendUpdateRequest.getUserId();
        Long friendId = friendUpdateRequest.getFriendId();
        Integer oneOrTwo = friendUpdateRequest.getOneOrTwo();
        if (id == null || userId == null || friendId == null || oneOrTwo == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能为空");
        }
        boolean remove = removeById(id);
        if (!remove) throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除失败!");
        String key = FRIENDS_LIST_KEY + userId + ":friend";
        stringRedisTemplate.delete(key + friendId);
        if (oneOrTwo == 2) {
            QueryWrapper<Friends> friendsQueryWrapper = new QueryWrapper<>();
            friendsQueryWrapper.eq("userId", friendId).eq("friendId", userId);
            remove = remove(friendsQueryWrapper);
            key = FRIENDS_LIST_KEY + friendId + ":friend";
            stringRedisTemplate.delete(key + userId);
        }
        return remove;
    }

    @Override
    public FriendsVO isFriend(Long userId, Long friendId) {
        String key = FRIENDS_LIST_KEY + userId;
        String endKey = key + ":friend" + friendId;
        Set<String> keys = stringRedisTemplate.keys(key + ":*");
        QueryWrapper<Friends> queryWrapper = new QueryWrapper<>();
        if (keys != null) {
            for (String k : keys) {
                if (k.equals(endKey)) {
                    Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(k);
                    return BeanUtil.fillBeanWithMap(map, new FriendsVO(), false);
                }
            }
            Friends one = getOne(queryWrapper.eq("userId", userId).eq("friendId", friendId));
            if (one == null) return null;
            return BeanUtil.copyProperties(one, FriendsVO.class);
        }
        return null;
    }

    @Override
    public List<Long> getMyFriendId(Long userId) {
        String key = FRIENDS_LIST_KEY + userId;
        List<Long> list = new ArrayList<>();
        Set<String> keys = stringRedisTemplate.keys(key + ":*");
        if (keys != null && !keys.isEmpty()) {
            for (String k : keys) {
                Object friendId = stringRedisTemplate.opsForHash().get(k, "friendId");
                list.add(Long.valueOf(String.valueOf(friendId)));
            }
        } else {
            List<Friends> friendsList = list(new QueryWrapper<Friends>().eq("userId", userId));
            list = friendsList.stream().map(Friends::getFriendId).collect(Collectors.toList());
        }
        return list;
    }

}
